/*
 * Copyright 2006 Berry Crawford
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.judo.generate.java;

import java.util.ArrayList;

import org.judo.generate.CodeGenerator;
import org.judo.generate.GenerationException;

public class Method implements CodeGenerator
{
	protected String visibility = "public";
	protected String methodName;
	protected boolean staticMethod = false;
	protected boolean generateBody = true;
	protected String returnType = "void";
	
	protected String freeFormCode = "";
	
	ArrayList statements = new ArrayList();
	ArrayList params = new ArrayList();
	ArrayList exceptions = new ArrayList();
	String tab = "\t";
	
	protected ArrayList<String> annotations = new ArrayList<String>();
	
	public void addFreeFormCode(String code)
	{
		freeFormCode += code;
	}
	
	public void addAnnototation(String annotationCode)
	{
		annotations.add(annotationCode);
	}
	
	
	
	public static Method methodStubFromInterface(Class interfaceType,String methodName)
	{
		java.lang.reflect.Method mthds[] = 
			interfaceType.getDeclaredMethods();
		
		for (int i=0;i<mthds.length;i++)
		{
			java.lang.reflect.Method method = mthds[i];
			
			if (method.getName().equals(methodName))
			{
				Method methodGen = new Method();
				
				methodGen.setMethodName(method.getName());
				methodGen.setReturnType(method.getReturnType().getCanonicalName());
				
				Class paramTypes[] = method.getParameterTypes();
				
				for (int j=0;j<paramTypes.length;j++)
				{
					methodGen.addParams(
							new ParamDefinition(paramTypes[j].getCanonicalName(),"param"+(j+1)));
				}
				
				Class exTypes[] = method.getExceptionTypes();
				
				for (int j=0;j<exTypes.length;j++)
				{
					methodGen.addExceptions(exTypes[j].getCanonicalName());
				}
				
				return methodGen;
			}
		}
		
		return null;
	}
	
	public static Method methodImplementationFromInterface(Class interfaceType,String methodName)
	{
		java.lang.reflect.Method mthds[] = 
			interfaceType.getDeclaredMethods();
		
		for (int i=0;i<mthds.length;i++)
		{
			java.lang.reflect.Method method = mthds[i];
			
			if (method.getName().equals(methodName))
			{
				Method methodGen = new Method();
				
				methodGen.setMethodName(method.getName());
				methodGen.setReturnType(method.getReturnType().getCanonicalName());
				
				Class paramTypes[] = method.getParameterTypes();
				
				for (int j=0;j<paramTypes.length;j++)
				{
					methodGen.addParams(
							new ParamDefinition(paramTypes[j].getCanonicalName(),"param"+(j+1)));
				}
				
				Class exTypes[] = method.getExceptionTypes();
				
				for (int j=0;j<exTypes.length;j++)
				{
					methodGen.addExceptions(exTypes[j].getCanonicalName());
				}
				
				String returnType = method.getReturnType().toString();
				
				if (!returnType.equals("void"))
					methodGen.addStatement(new SingleStatement(2,"return null;"));
				
				return methodGen;
			}
		}
		
		return null;
	}
	
	public String generate() throws GenerationException
	{
		String result = "";
	
		for (String annotation:annotations)
			result += tab+annotation+"\n";
		
		result += tab+visibility+" ";
		
		if (staticMethod)
			result += "static ";
		
		result += returnType + " " + methodName +"(";
		
		boolean first = true;
		
		for (int i=0;i<params.size();i++)
		{
			if (first)
				first = false;
			else
				result += ",";
			
			result += ((ParamDefinition)params.get(i)).generate();
		}
		
		result += ") ";
		
		if (exceptions.size() > 0)
		{
			result += "throws ";
			
			first = true;
			
			for (int i=0;i<exceptions.size();i++)
			{
				if (first)
					first = false;
				else
					result += ",";
				
				result += exceptions.get(i);
			}
		}
		
		if (generateBody)
		{
			result += "\n"+tab+"{\n";
			
			for (int i=0;i<statements.size();i++)
			{
				JavaStatement statement = (JavaStatement)statements.get(i);
				result += statement.generate();
			}
			
			result += freeFormCode;
			result += tab +"}\n\n";
		}
		else
		{
			result += ";\n";
		}
		
		return result;
	}
	
	public void addStatement(JavaStatement statement)
	{
		statements.add(statement);
	}
	
	public void addParams(ParamDefinition param)
	{
		params.add(param);
	}
	
	public void addExceptions(String exception)
	{
		exceptions.add(exception);
	}

	public String getReturnType()
	{
		return returnType;
	}

	public void setReturnType(String returnType)
	{
		this.returnType = returnType;
	}

	public boolean isStaticMethod()
	{
		return staticMethod;
	}

	public void setStaticMethod(boolean staticMethod)
	{
		this.staticMethod = staticMethod;
	}

	public String getVisibility()
	{
		return visibility;
	}

	public void setVisibility(String visibility)
	{
		this.visibility = visibility;
	}

	public String getMethodName()
	{
		return methodName;
	}

	public void setMethodName(String methodName)
	{
		this.methodName = methodName;
	}

	public boolean isGenerateBody()
	{
		return generateBody;
	}

	public void setGenerateBody(boolean generateBody)
	{
		this.generateBody = generateBody;
	}
}
